//
//  QLViewController.m
//  Test
//
//  Created by Shrek on 15/5/12.
//  Copyright (c) 2015年 Personal. All rights reserved.
//

#import "QLViewController.h"

#define QLGlobalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define QLMainQueue dispatch_get_main_queue()

@interface QLViewController ()
{
    __weak IBOutlet UIButton *_button;
    __weak IBOutlet UIImageView *_imageView;
}

@end

@implementation QLViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self queueGroup];
}

#pragma mark - 队列组
- (void)queueGroup {
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = QLGlobalQueue;
    __block UIImage *image = nil;
    __block UIImage *logo = nil;
    dispatch_group_async(group, queue, ^{
        NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/w%3D230/sign=d4b82d65544e9258a63481edac83d1d1/fd039245d688d43f5a0f54f37f1ed21b0ef43b09.jpg"]];
        image = [UIImage imageWithData:imageData];
    });
    dispatch_group_async(group, queue, ^{
        NSData *logoData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"]];
        logo = [UIImage imageWithData:logoData];
    });
    
    dispatch_group_notify(group, queue, ^{
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
        [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
        [logo drawInRect:CGRectMake(image.size.width-100, image.size.height-80, 100, 80)];
        UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        dispatch_async(QLMainQueue, ^{
            [_imageView setImage:finalImage];
        });
    });
}

#pragma mark - 一次性代码
- (void)executeOnce {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // code to be executed once
    });
}

#pragma mark - 延迟执行
- (void)delayExcute {
    dispatch_queue_t queue = dispatch_get_main_queue(); // 可以替换为全局队列
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"%@", @"");
    });
}

#pragma mark - 线程间的通讯
- (void)downloadImageSetToButton {
    dispatch_async(QLGlobalQueue, ^{
        NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/w%3D230/sign=d4b82d65544e9258a63481edac83d1d1/fd039245d688d43f5a0f54f37f1ed21b0ef43b09.jpg"]];
        UIImage *image = [UIImage imageWithData:imageData];
        dispatch_async(QLMainQueue, ^{
            [_button setBackgroundImage:image forState:UIControlStateNormal];
        });
    });
}


/* ==================================================================================================== */
#pragma mark - 同步异步与队列的各种组合
/**
 *  总结
 *  1,只要是异步,就会开线程,否则就不会开线程
 *  2,多个任务在同一串行线程中执行,就只会有一条线程
 */

/**
 *  async -- 并发队列（最常用）
 *  会不会创建线程：会，一般同时开多条
 *  任务的执行方式：并发执行
 */
- (void)asyncGlobalQueue
{
    // 获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 将 任务 添加 全局队列 中去 异步 执行
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
    });
}

/**
 *  async -- 串行队列（有时候用）
 *  会不会创建线程：会，一般只开1条线程
 *  任务的执行方式：串行执行（一个任务执行完毕后再执行下一个任务）
 */
- (void)asyncSerialQueue
{
    // 1.创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
    
    // 2.将任务添加到串行队列中 异步 执行
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
    });
    
    // 3.非ARC，需要释放创建的队列
    //    dispatch_release(queue);
}

/**
 *  async -- 主队列(很常用)
 */
- (void)asyncMainQueue
{
    // 1.主队列(添加到主队列中的任务，都会自动放到主线程中去执行)
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 2.添加 任务 到主队列中 异步 执行
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
    });
}

/**
 *  sync -- 主队列(不能用---会卡死)
 */
- (void)syncMainQueue
{
    NSLog(@"syncMainQueue----begin--");
    
    // 1.主队列(添加到主队列中的任务，都会自动放到主线程中去执行)
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 2.添加 任务 到主队列中 异步 执行
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    
    NSLog(@"syncMainQueue----end--");
}

/**
 *  sync -- 并发队列
 *  会不会创建线程：不会
 *  任务的执行方式：串行执行（一个任务执行完毕后再执行下一个任务）
 *  并发队列失去了并发的功能
 */
- (void)syncGlobalQueue
{
    // 获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 将 任务 添加到 全局并发队列 中 同步 执行
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
    });
}

/**
 *  sync -- 串行队列
 *  会不会创建线程：不会
 *  任务的执行方式：串行执行（一个任务执行完毕后再执行下一个任务）
 */
- (void)syncSerialQueue
{
    // 创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
    
    // 将 任务 添加到 串行队列 中 同步 执行
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片2---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片3---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片4---%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"-----下载图片5---%@", [NSThread currentThread]);
    });
}

// dispatch_sync : 同步，不具备开启线程的能力
// dispatch_async : 异步，具备开启线程的能力

// 并发队列 ：多个任务可以同时执行
// 串行队列 ：一个任务执行完后，再执行下一个任务

// Foundation :  OC
// Core Foundation : C语言
// Foundation和Core Foundation框架的数据类型可以互相转换的
/*
    NSString *str = @"123"; // Foundation
    CFStringRef str2 = (__bridge CFStringRef)str; // Core Foundation
    NSString *str3 = (__bridge NSString *)str2;
    CFArrayRef ---- NSArray
    CFDictionaryRef ---- NSDictionary
    CFNumberRef ---- NSNumber

    Core Foundation中手动创建的数据类型，都需要手动释放
    CFArrayRef array = CFArrayCreate(NULL, NULL, 10, NULL);
    CFRelease(array);


    CGPathRef path = CGPathCreateMutable();
    CGPathRetain(path);

    CGPathRelease(path);
    CGPathRelease(path);
 */
/**
 凡是函数名中带有create\copy\new\retain等字眼, 都应该在不需要使用这个数据的时候进行release
 GCD的数据类型在ARC环境下不需要再做release
 CF(Core Foundation)的数据类型在ARC\MRC环境下都需要再做release
 */

@end
